
#include <BRestraint>
#include "member_BRestraint.h"
#include "member_BGroup.h"
#include "member_BBody.h"
#include "member_BObject.h"

using namespace BWE;

#define member					(*(member_BRestraint*)_ptr)
#define member_allocate()		_ptr = new member_BRestraint(this)
#define member_release()		delete (member_BRestraint*)_ptr

BRestraint::BRestraint()
{
	member_allocate();
}
BRestraint::BRestraint(const BString& name) : BObject(name)
{
	member_allocate();
}
BRestraint::BRestraint(BBody* bodyA, BBody* bodyB)
{
	member_allocate();
	if (bodyA)
	{
		member.bodyA = bodyA;
		body_member(bodyA)->restraints.insert(this);
		object_member(bodyA)->emit(Signal_Attached, BValue(this, true));
	}
	if (bodyB)
	{
		member.bodyB = bodyB;
		body_member(bodyB)->restraints.insert(this);
		object_member(bodyB)->emit(Signal_Attached, BValue(this, true));
	}
}
BRestraint::BRestraint(BBody* bodyA, const BVector& pivotA)
{
	member_allocate();
	if (bodyA)
	{
		member.bodyA = bodyA;
		body_member(bodyA)->restraints.insert(this);
		object_member(bodyA)->emit(Signal_Attached, BValue(this, true));
	}
	member.pivotA = pivotA;
}
BRestraint::BRestraint(BBody* bodyA, const BVector& pivotA, const BVector& pivotB)
{
	member_allocate();
	if (bodyA)
	{
		member.bodyA = bodyA;
		body_member(bodyA)->restraints.insert(this);
		object_member(bodyA)->emit(Signal_Attached, BValue(this, true));
	}
	member.pivotA = pivotA;
	member.pivotB = pivotB;
}
BRestraint::BRestraint(BBody* bodyA, const BVector& pivotA, BBody* bodyB, const BVector& pivotB)
{
	member_allocate();
	if (bodyA)
	{
		member.bodyA = bodyA;
		body_member(bodyA)->restraints.insert(this);
		object_member(bodyA)->emit(Signal_Attached, BValue(this, true));
	}
	member.pivotA = pivotA;
	if (bodyB)
	{
		member.bodyB = bodyB;
		body_member(bodyB)->restraints.insert(this);
		object_member(bodyB)->emit(Signal_Attached, BValue(this, true));
	}
	member.pivotB = pivotB;
}
BRestraint::~BRestraint()
{
	if (BBody* bodyA = member.bodyA)
	{
		body_member(bodyA)->restraints.remove(this);
		object_member(bodyA)->emit(Signal_Detached, BValue(this, true));
	}
	if (BBody* bodyB = member.bodyB)
	{
		body_member(bodyB)->restraints.remove(this);
		object_member(bodyB)->emit(Signal_Detached, BValue(this, true));
	}
	member_release();
}

void BRestraint::copy(const BRestraint* other)
{
	object_member(this)->name = object_member(other)->name;
	member.bodyA = restraint_member(other)->bodyA;
	member.pivotA = restraint_member(other)->pivotA;
	member.bodyB = restraint_member(other)->bodyB;
	member.pivotB = restraint_member(other)->pivotB;
	member.colliding = restraint_member(other)->colliding;
	member.breakImpulse = restraint_member(other)->breakImpulse;
	if (BBody* bodyA = member.bodyA)
	{
		body_member(bodyA)->restraints.insert(this);
		object_member(bodyA)->emit(Signal_Attached, BValue(this, true));
	}
	if (BBody* bodyB = member.bodyB)
	{
		body_member(bodyB)->restraints.insert(this);
		object_member(bodyB)->emit(Signal_Attached, BValue(this, true));
	}
}
BRestraint* BRestraint::clone() const
{
	BRestraint* restraint = new BRestraint();
	restraint->copy(this);
	return restraint;
}

void BRestraint::setGroup(BGroup* group)
{
	if (group && member.group != group)
	{
		group->insert(this);
	}
}
BGroup* BRestraint::group() const
{
	return member.group;
}

void BRestraint::setBodyA(BBody* bodyA, const BVector& pivotA)
{
	setBodyA(bodyA);
	setPivotA(pivotA);
}
void BRestraint::setBodyA(BBody* bodyA)
{
	if (member.bodyA != bodyA)
	{
		if (BBody* body = member.bodyA)
		{
			body_member(body)->restraints.remove(this);
			object_member(body)->emit(Signal_Detached, BValue(this, true));
		}
		member.bodyA = bodyA;
		if (BBody* body = member.bodyA)
		{
			body_member(body)->restraints.insert(this);
			object_member(body)->emit(Signal_Attached, BValue(this, true));
		}
		this->emit(Signal_BodyAChanged, bodyA);
	}
}
BBody* BRestraint::bodyA() const
{
	return member.bodyA;
}

void BRestraint::setBodyB(BBody* bodyB, const BVector& pivotB)
{
	setBodyB(bodyB);
	setPivotB(pivotB);
}
void BRestraint::setBodyB(BBody* bodyB)
{
	if (member.bodyB != bodyB)
	{
		if (BBody* body = member.bodyB)
		{
			body_member(body)->restraints.remove(this);
			object_member(body)->emit(Signal_Detached, BValue(this, true));
		}
		member.bodyB = bodyB;
		if (BBody* body = member.bodyB)
		{
			body_member(body)->restraints.insert(this);
			object_member(body)->emit(Signal_Attached, BValue(this, true));
		}
		this->emit(Signal_BodyBChanged, bodyB);
	}
}
BBody* BRestraint::bodyB() const
{
	return member.bodyB;
}

bool BRestraint::setPivotA(BReal px, BReal py, BReal pz)
{
	return setPivotA(BVector(px, py, pz));
}
bool BRestraint::setPivotA(const BVector& pivotA)
{
	if (member.pivotA != pivotA)
	{
		member.pivotA = pivotA;
		this->emit(Signal_PivotAChanged, pivotA);
		return true;
	}
	return false;
}
const BVector& BRestraint::pivotA() const
{
	return member.pivotA;
}

bool BRestraint::setPivotB(BReal px, BReal py, BReal pz)
{
	return setPivotB(BVector(px, py, pz));
}
bool BRestraint::setPivotB(const BVector& pivotB)
{
	if (member.pivotB != pivotB)
	{
		member.pivotB = pivotB;
		this->emit(Signal_PivotBChanged, pivotB);
		return true;
	}
	return false;
}
const BVector& BRestraint::pivotB() const
{
	return member.pivotB;
}

void BRestraint::setColliding(bool colliding)
{
	if (member.colliding != colliding)
	{
		member.colliding = colliding;
		this->emit(Signal_Changed);
	}
}
bool BRestraint::colliding() const
{
	return member.colliding;
}

void BRestraint::setBreakImpulse(BReal breakImpulse)
{
	if (member.breakImpulse != breakImpulse)
	{
		member.breakImpulse = breakImpulse;
		this->emit(Signal_Changed);
	}
}
BReal BRestraint::breakImpulse() const
{
	return member.breakImpulse;
}

bool BRestraint::contain(const BBody* body) const
{
	return member.bodyA == body || member.bodyB == body;
}
BBody* BRestraint::another(const BBody* body)
{
	if (body)
	{
		if (member.bodyA == body)
			return member.bodyB;
		if (member.bodyB == body)
			return member.bodyA;
	}
	return 0;
}
const BBody* BRestraint::another(const BBody* body) const
{
	if (body)
	{
		if (member.bodyA == body)
			return member.bodyB;
		if (member.bodyB == body)
			return member.bodyA;
	}
	return 0;
}

void BRestraint::clear()
{
	bool changed = false;
	if (BBody* body = member.bodyA)
	{
		body_member(body)->restraints.remove(this);
		member.bodyA = 0;
		member.pivotA.reset();
		changed = true;
	}
	if (BBody* body = member.bodyB)
	{
		body_member(body)->restraints.remove(this);
		member.bodyB = 0;
		member.pivotB.reset();
		changed = true;
	}
	if (changed)
	{
		this->emit(Signal_Changed);
	}
}

int BRestraint::solverSize()
{
	return 0;
}
void BRestraint::soverItems(BSolverItem* solverItems, BReal stepTime)
{

}
